
#define _DEBUG_OUTPUT_ true 
#define LOG_TAG "[GetFace]"

#include "BaseData.h"
#include "OpenCVFacialDetectorBase.h"
#include "GetFace.h"

using namespace cv;
using namespace std;
using namespace facial_compal;

//for dir_operations()
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <stddef.h>
#include <fcntl.h>
#include <dirent.h>

//for dlxxx functions
#include <dlfcn.h>

vector<string> & getImageFilesNameVectUnderDir(vector<string> &imageNameVect, const string strDir) {

	DIR *dirp = NULL;
	struct dirent *direntp = NULL;
	dirp = opendir(strDir.c_str());
    assert(NULL != dirp);

    for (int i = 0; ;) {
        direntp = readdir(dirp);
        if (direntp != NULL) {
            string filename(direntp->d_name);
            if(filename.find(".jpg") != string::npos 
            || filename.find(".jpeg") != string::npos 
            || filename.find(".bmp") != string::npos 
            || filename.find(".png") != string::npos 
            || filename.find(".pgm") != string::npos) {

                string absPath = strDir + "/" + filename;
                imageNameVect.push_back(filename);
                /* show them
                    char window_name[64];
                    sprintf(window_name, "window_%d", i);
                    cvNamedWindow(window_name, CV_WINDOW_AUTOSIZE);
                    cvShowImage(window_name, iplImageVect[i]);
                    cvWaitKey();
                */
                i ++;
            }
        } else {
            break;
        }
    }
    closedir(dirp);
    return imageNameVect;
}

int main(int argc, char **argv) {

    OpenCVFacialDetectorBase *pDetector = new OpenCVFacialDetectorBase("/usr/local/share/OpenCV/haarcascades/");
    vector<Rect> rects;
    vector<string> args;

    vector<string> imageFileNames;
    VideoCapture cap;   

    Mat frame;
    bool isFromCam = true;
    bool isImageSourceEnsured = false;

    int option = -1;
    char *d_option_arg = NULL;
    char *plugin_name = NULL;
    while((option = getopt(argc, argv, "cd:p:") )!= -1) {
        switch (option) {
        case 'c':
            isFromCam = true;
            isImageSourceEnsured = true;
            break;
        case 'd':
            isFromCam = false;
            isImageSourceEnsured = true;
            d_option_arg = optarg;
            break;
        case 'p':
            plugin_name = optarg;
            break;
        case '?':
            exit(-1);
        }
    }

    cdebug( "**********************************************************************\n"
            "%s args: -cdp\n"
            "\t\t -c:               Use Image Grap From Camera\n"
            "\t\t OR\n"
            "\t\t -d <directory>:   Use Image Read From <directory>\n"
            "\t\t -p <plugin_name>: Load <plugin_name> for Processing Face Image\n"
            "\t\t !!! Other strings is passed to plugin with no change !!!\n"
            "\t\t !!! Some Plugins may need addition arguments to work properly !!!\n", argv[0]);
    cdebug( "**********************************************************************\n");

    assert(isImageSourceEnsured);

    if(isFromCam) {
        cdebug("will grap image from webcam\n");
        cap.open(0);
    } else {
        cdebug("will grap images from %s/\n", d_option_arg);
        imageFileNames = getImageFilesNameVectUnderDir(imageFileNames, d_option_arg);
        assert(imageFileNames.size() > 0);
    }

    if(plugin_name != NULL) {
        cdebug("will load plugin:%s\n", plugin_name);
        cdebug("passed to plugin:\n");
        for(int i = optind; i < argc; i ++) {
            args.push_back(argv[i]);
            cdebug("\t%s\n", argv[i]);
        }
        cdebug("\n");
    } else {
        cdebug("no face processer plugin passed in\n");
    }


    //载入插件 ++++++++++++++++
    creatFaceMatProcessor       *pCreatePlugin = NULL;
    destroyFaceMatProcessor     *pDestroyPlugin = NULL;
    FaceMatProcessor            *pProcessor = NULL;

    void *pDl = NULL;
    if(NULL != plugin_name) {
        pDl = dlopen(plugin_name, RTLD_LAZY);
        if (!pDl) {
            edebug("Cannot load library: %s\n" ,dlerror() );
        } else {

            // reset errors
            dlerror();
            // load the symbols
            pCreatePlugin = (creatFaceMatProcessor*) dlsym(pDl, "plugin_create");
            const char* dlsym_error = dlerror();
            if (dlsym_error) {
                edebug("Cannot load symbol plugin_create: %s\n", dlsym_error) ;
            }
            pDestroyPlugin = (destroyFaceMatProcessor*) dlsym(pDl, "plugin_destroy");
            dlsym_error = dlerror();
            if (dlsym_error) {
                edebug("Cannot load symbol plugin_destroy: %s\n", dlsym_error) ;
            }

            if(NULL != pCreatePlugin) {
                pProcessor = pCreatePlugin();
            }
        }
    }


    //载入插件 ---------------

    namedWindow("frame");
    //namedWindow("detected");
    for(unsigned int loop_count = 0; waitKey(5) != 27; loop_count ++) {
        string absPath("");
        if(!isFromCam) {
            absPath = absPath + d_option_arg + "/" + imageFileNames[loop_count];
            frame = imread(absPath, -1/*see http://goo.gl/J5egE */);
            cdebug("loaded %s\n", absPath.c_str()); 

            if(loop_count >= imageFileNames.size() - 1 ) {
                break;
            }
        } else {
            cap >> frame;
        }

        imshow("frame", frame);
        pDetector -> facial_detect(frame, rects, FACE_FACE);
        //cdebug("detected %ld faces\n", rects.size());

        #if 0
        if(rects.size() > 0) {
            int width_max = 0;
            int width_max_i;
            for(unsigned int i = 0; i < rects.size(); i ++) {
                if(width_max < rects[i].width)  {
                    width_max = rects[i].width;
                    width_max_i = i;
                }
            }
            Mat matFace(frame, rects[width_max_i]);
            //imshow("detected", matFace);
            if(pProcessor!= NULL) {
                if( 0 > pProcessor ->process(matFace, args)) {
                    break;
                }

            }
        } else {
            if(!isFromCam) {
                edebug("\t\t\t\tface not found!!\n");
            }
        }
        #endif
        for(size_t i = 0; i < rects.size(); i ++){
            Mat matFace(frame, rects[i]);
            if(pProcessor!= NULL) {
                if( 0 > pProcessor ->process(matFace, args)) {
                    break;
                }
            }
        }

        if(NULL != pProcessor) {
            if( 0 > pProcessor ->processOriginal(frame, args)) {
                break;
            }
        }

        //waitKey(0);
    }

    delete pDetector;
    if (NULL != pDestroyPlugin) {pDestroyPlugin(pProcessor);};
    if (NULL != pDl) {dlclose(pDl);};
    return 0;
}
